﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data.Objects;
using System.IO;
using System.Linq;
using System.Threading;
using Citi.EmailSender.Domain;
using Citi.EmailSender.Domain.Utils;
using Citi.Helpers;

namespace Citi.EmailSender.WCF
{
    public class Email : IEmail
    {
        private readonly string tempFolder = ConfigurationManager.AppSettings["TempFolder"];
        private readonly string downloadTempFolder = ConfigurationManager.AppSettings["DownloadTempFolder"];
        private string NetworkUser { get { return ConfigurationManager.AppSettings["NetworkUser"]; } }
        private string NetWorkPassword { get { return ConfigurationManager.AppSettings["NetWorkPassword"]; } }
        private string WebUrl { get { return ConfigurationManager.AppSettings["WebUrl"]; } }
        private string Proxy { get { return ConfigurationManager.AppSettings["Proxy"]; } }
        private string NetworkDomain { get { return ConfigurationManager.AppSettings["NetworkDomain"]; } }

        public string DownloadAttachment(DataContract.DownloadAttachment downloadAttachment)
        {
            var application = new Application().SelectByIdOrName(downloadAttachment.ApplicationId, downloadAttachment.ApplicationName);
            if (application == null) throw new Exception("Application not found.");

            var downloadDomain = new DownloadAttachment
                {
                    ApplicationId = application.Id,
                    ApplicationUniqueKey = Guid.NewGuid().ToString(),
                    DefaultFolder = (int)downloadAttachment.DefaultFolder,
                    From = downloadAttachment.From,
                    InitialDate = downloadAttachment.InitialDate,
                    NonDefaultFolder = downloadAttachment.NonDefaultFolder,
                    Subject = downloadAttachment.Subject,
                    DownloadFolder = string.Concat(downloadAttachment.Subject.Length > 30
                                                       ? downloadAttachment.Subject.Substring(0, 30)
                                                       : downloadAttachment.Subject,
                                                   DateTime.Now.ToString("yyyyMMdd hhmmss")),
                    PartialFileName = downloadAttachment.PartialFileName,
                    FileExtensions = downloadAttachment.FileExtensions != null ? string.Join("|", downloadAttachment.FileExtensions) : null
                };

            downloadDomain.Save(downloadDomain);

            while (downloadDomain.DownloadedOn == null)
            {
                Context.Instance.DownloadAttachments.MergeOption = MergeOption.OverwriteChanges;
                downloadDomain = downloadDomain.SelectById<DownloadAttachment>(downloadDomain.Id);
                //Context.Instance.LoadProperty(downloadDomain, x => x.DownloadedOn, MergeOption.OverwriteChanges);

                if (downloadDomain.DownloadedOn != null) break;

                Thread.Sleep(3000);
            }

            var pathDownloaded = Path.Combine(downloadTempFolder, downloadDomain.DownloadFolder);
            var serverName = downloadTempFolder.Split(new[] { "/", @"\\", @"\" }, StringSplitOptions.RemoveEmptyEntries).First();

            using (NetworkShareAccesser.Access(serverName, NetworkUser, NetWorkPassword))
            {
                return Directory.Exists(pathDownloaded) ? pathDownloaded : null;
            }
        }

        public string InsertEmailInQueue(DataContract.Email emailData)
        {
            try
            {
                var emailDomain = FillDomainEmail(emailData);
                emailDomain.Save(emailDomain);

                return emailDomain.ApplicationUniqueKey;
            }
            catch (Exception e)
            {
                File.WriteAllText(Path.Combine(tempFolder, "Error.txt"), e.Message
                    + (e.InnerException != null ? e.InnerException.Message : string.Empty) + e.StackTrace);
                throw;
            }
        }

        private Domain.Email FillDomainEmail(DataContract.Email emailData)
        {
            var email = new Domain.Email
              {
                  CreatedDate = DateTime.Now,
                  ApplicationUniqueKey = Guid.NewGuid().ToString(),
                  Approved = !emailData.NeedApprovalToSend.HasValue || !emailData.NeedApprovalToSend.Value ? true : (bool?)null,
                  ScheduleDate = emailData.ScheduleDateTime
              };

            if (emailData.TemplateId != 0)
                email.EmailDataId = emailData.TemplateId;
            else
            {
                var onBehalfOf = new OnBehalfOf().GetByAddress(emailData.SentOnBehalfOfName);
                if (onBehalfOf == null) throw new Exception("Sent On Behalf Of Name not found.");

                var application = new Application().SelectByIdOrName(emailData.ApplicationId, emailData.ApplicationName);
                if (application == null) throw new Exception("Application not found.");

                email.EmailData = new EmailData
                    {
                        Application = application,
                        Body = emailData.BodyMessage,
                        Subject = emailData.Subject,
                        Importance = (int)emailData.Importance,
                        OnBehalfOfId = onBehalfOf.Id,
                        ApplicationId = application.Id,
                        Active = true,
                        ApplicationKey = Guid.NewGuid().ToString(),
                        Url = emailData.Url
                    };
            }
            SetParameters(emailData, email);

            if (emailData.Attachments != null)
                emailData.Attachments.ForEach(x => email.Attachments.Add(new Attachment { Path = x.PathFile }));

            SetEmailReceivers(emailData, email);

            return email;
        }

        private static void SetParameters(DataContract.Email emailData, Domain.Email email)
        {
            var parameters = emailData.TemplateId != 0
                ? new EmailDataParameter().SelectByEmailData(emailData.TemplateId)
                : new List<EmailDataParameter>();

            emailData.Parameters.ToList().ForEach(x =>
                {
                    if (parameters.FirstOrDefault(y => y.Name == x.Key) != null)
                    {
                        email.EmailParameters.Add(
                            new EmailParameter
                            {
                                ParameterId = parameters.FirstOrDefault(y => y.Name == x.Key).Id,
                                Value = x.Value
                            });
                    }
                    else
                    {
                        email.EmailParameters.Add(
                             new EmailParameter
                                {
                                    EmailDataParameter = new EmailDataParameter { Name = x.Key, EmailDataId = email.EmailDataId },
                                    Value = x.Value
                                }
                            );
                    }
                });
        }

        private static void SetEmailReceivers(DataContract.Email emailData, Domain.Email email)
        {
            SetEmailReceivers(email, emailData.Bcc, Enums.EmailReceiverType.Bcc);
            SetEmailReceivers(email, emailData.To, Enums.EmailReceiverType.To);
            SetEmailReceivers(email, emailData.Cc, Enums.EmailReceiverType.Cc);
            SetEmailReceivers(email, emailData.Approvers, Enums.EmailReceiverType.Approver);
        }

        private static void SetEmailReceivers(Domain.Email email, List<DataContract.EmailAddress> emailAddresses, Enums.EmailReceiverType type)
        {
            if (emailAddresses == null) return;

            emailAddresses.ForEach(x =>
                {
                    if (string.IsNullOrWhiteSpace(x.Description)) return;

                    email.EmailReceivers.Add(new EmailReceiver
                        {
                            EmailAddress = new EmailAddress().GetByAddress(x.Description) ?? new EmailAddress { Address = x.Description },
                            Type = (int)type
                        });
                });
        }

        public string GetTemplateById(int id)
        {
            var email = new EmailData().SelectById<EmailData>(id);

            return ReturnHtml(email);
        }

        private string ReturnHtml(EmailData email)
        {
            if (!string.IsNullOrEmpty(email.Body))
                return email.Body;

            if (!string.IsNullOrEmpty(email.Url))
            {
                var url = !email.Url.StartsWith("http") ? string.Concat(WebUrl, email.Url) : email.Url;
                return EmailHelper.GetEmailBody(url, NetworkUser, NetWorkPassword, NetworkDomain, Proxy);
            }

            return string.Empty;
        }

        public string GetTemplateByApplicationUniqueKey(string application, string applicationUniqueKey)
        {
            var email = new EmailData().SelectTemplates()
                .FirstOrDefault(x => x.ApplicationUniqueKey == applicationUniqueKey
                && (x.Application.FullName.ToUpper() == application.ToUpper() 
                        || x.Application.Abbreviation.ToUpper() == application.ToUpper()
                        || x.Application.Acronym.ToUpper() == application.ToUpper()));

            return email == null ? null : ReturnHtml(email);
        }
    }
}
